﻿namespace Sidvall.CodeGenerator
{
    public class DomainObjectRelationCollection : System.Collections.ObjectModel.KeyedCollection<string, DomainObjectRelation>
    {
        #region Public Members

        #region Add

        public DomainObjectRelation Add(DomainObject sourceObject, DomainObject relatedObject, Multiplicity sourceObjectMultiplicity, Multiplicity relatedObjectMultiplicity,
            string name, string sourceObjectPropertyName1, string relatedObjectPropertyName1, string sourceObjectPropertyName2, string relatedObjectPropertyName2,
            string sourceObjectPropertyName3, string relatedObjectPropertyName3, string sourceObjectPropertyName4, string relatedObjectPropertyName4)
        {
            var domainObjectRelation = new DomainObjectRelation(sourceObject, relatedObject)
            {
                SourceObjectMultiplicity = sourceObjectMultiplicity,
                RelatedObjectMultiplicity = relatedObjectMultiplicity,
                Name = name,
                NameInDataStore = string.Empty,
                IsDatabaseOnly = false,
                CascadeDelete = false,
            };
            switch (domainObjectRelation.RelatedObjectMultiplicity)
            {
                case Multiplicity.Many:
                    domainObjectRelation.NameIsPlural = true;
                    break;
                default:
                    domainObjectRelation.NameIsPlural = false;
                    break;
            }
            if (string.IsNullOrWhiteSpace(domainObjectRelation.Name))
            {
                switch (domainObjectRelation.RelatedObjectMultiplicity)
                {
                    case Multiplicity.Many:
                        domainObjectRelation.Name = TypeMapper.GetPluralName(relatedObject.Name);
                        break;
                    default:
                        domainObjectRelation.Name = TypeMapper.GetSingularName(relatedObject.Name);
                        break;
                }
                if (domainObjectRelation.Name == sourceObject.Name)
                {
                    domainObjectRelation.Name = "Parent" + domainObjectRelation.Name;
                }
                if (sourceObject.Properties.Contains(domainObjectRelation.Name))
                {
                    domainObjectRelation.Name += "Relation";
                }
            }
            AddField(domainObjectRelation, sourceObject, relatedObject, sourceObjectPropertyName1, relatedObjectPropertyName1);
            AddField(domainObjectRelation, sourceObject, relatedObject, sourceObjectPropertyName2, relatedObjectPropertyName2);
            AddField(domainObjectRelation, sourceObject, relatedObject, sourceObjectPropertyName3, relatedObjectPropertyName3);
            AddField(domainObjectRelation, sourceObject, relatedObject, sourceObjectPropertyName4, relatedObjectPropertyName4);
            Add(domainObjectRelation);
            return domainObjectRelation;
        }

        #endregion
        #region FindByDomainObjectName

        public System.Collections.ObjectModel.Collection<DomainObjectRelation> FindByDomainObjectName(string name)
        {
            System.Collections.ObjectModel.Collection<DomainObjectRelation> items;

            items = new System.Collections.ObjectModel.Collection<DomainObjectRelation>();
            name = DomainObject.GetFullName(null, name);
            foreach (var item in this)
            {
                if (item.RelatedObject.FullName == name)
                    items.Add(item);
                else if (item.SourceObject.FullName == name)
                    items.Add(item);
            }
            return items;
        }

        #endregion
        #region GetKeyForItem

        protected override string GetKeyForItem(DomainObjectRelation item)
        {
            if (item == null)
                throw new System.ArgumentNullException("item");

            return DomainObjectRelation.GetKey(item);
        }

        #endregion
        #region Import

        public void Import(System.Collections.Generic.IEnumerable<DomainObjectRelation> items)
        {
            string key;

            if (items == null)
                return;

            foreach (var item in items)
            {
                key = DomainObjectRelation.GetKey(item);
                if (Contains(key))
                    this[key].Import(item);
                else
                    Add(item);
            }
        }

        #endregion
        #region RemoveItemsByDomainObjectNames

        public void RemoveItemsByDomainObjectNames(bool isDatabaseOnly, params string[] domainObjectNames)
        {
            System.Collections.ObjectModel.Collection<DomainObjectRelation> items;

            if (domainObjectNames == null)
                return;
            foreach (var domainObjectName in domainObjectNames)
            {
                items = FindByDomainObjectName(domainObjectName);
                foreach (var item in items)
                {
                    if (isDatabaseOnly)
                        item.IsDatabaseOnly = true;
                    else
                        Remove(item);
                }
            }
        }

        #endregion

        #endregion
        #region Private Members

        #region AddField

        private void AddField(DomainObjectRelation relation, DomainObject sourceObject, DomainObject relatedObject,
            string sourceObjectPropertyName, string relatedObjectPropertyName)
        {
            if (string.IsNullOrWhiteSpace(sourceObjectPropertyName))
                return;
            if (string.IsNullOrWhiteSpace(relatedObjectPropertyName))
                return;
            var sourceProperty = sourceObject.Properties.FindByName(sourceObjectPropertyName);
            if (sourceProperty == null)
                return;
            var relatedProperty = relatedObject.Properties.FindByName(relatedObjectPropertyName);
            if (relatedProperty == null)
                return;
            var domainObjectRelationField = new DomainObjectRelationField(sourceProperty, relatedProperty);
            relation.Fields.Add(domainObjectRelationField);
        }

        #endregion

        #endregion
        #region Constructors

        public DomainObjectRelationCollection()
            : base(System.StringComparer.OrdinalIgnoreCase)
        {
        }

        #endregion
    }
}
